using System;
using System.Collections.Generic;
using System.Text;
using System.Windows.Forms;
using Microsoft.Xna.Framework;
using Microsoft.Xna.Framework.Content;
using Microsoft.Xna.Framework.Graphics;

namespace GenericExampleParticleSystem
{
    class MarchingCubes : DrawableGameComponent
    {
        //data
        private GenericPointSpriteParticles data;
        private float window;
        private float max,min;
        
        //device stuff
        ContentManager content;
        GraphicsDeviceManager myDeviceManager;
        GraphicsDevice myDevice;
        
        //texture stuff
        string textureAsset;
        Texture2D myTexture;
        //shader stuff
        string shaderAsset;
        Effect effect;
        //view information
        Vector3 myPosition;
        Vector3 myScale;
        Quaternion myRotation;
        // vertex declaration for a triangle
        private VertexDeclaration posColTriangle;
        //Triangle Array
        VertexPositionColor[] vertices;
        private int WIDTH = 2;
        private int HEIGHT = 2;
        private VertexBuffer vb;
        private IndexBuffer ib;

        private float[] dataZ;
        private float[] dataX;
        private float[] dataY;

        private float location;



        //public MarchingCubes(double[] _data,int _window)
        public MarchingCubes (Game game, GraphicsDeviceManager graphiceDeviceManager, string texture, string shader,GenericPointSpriteParticles _data,float _window):base(game)
        {
            content = new ContentManager(game.Services);
            myDeviceManager = graphiceDeviceManager;

            //world view
            myPosition = Vector3.Zero;
            myScale = Vector3.One;
            myRotation = new Quaternion(0, 0, 0, 1);

            data = _data;
            window = _window;
            getDataXYZ();
            findMaxMin(dataZ);

            myDeviceManager = graphiceDeviceManager;
            textureAsset = texture;
            shaderAsset =  shader;

            location = March();


            

            
        }

        public void getDataXYZ()
        {
            dataZ = new float[data.partCount];
            dataX = new float[data.partCount];
            dataY = new float[data.partCount];
            for (int i = 0; i < data.partCount; i++)
            {
                dataZ[i] = data.getParticle(i).Z;
                dataX[i] = data.getParticle(i).X;
                dataY[i] = data.getParticle(i).Y;
            }
            
        }


        protected override void UnloadContent()
        {
            content.Unload();
            base.UnloadContent();
        }


        public float March()
        {
            int result = 0;
            float highValue=0;
            float x = min;
            float y = max;
            //debug only
            //window = 0.1f;
            window = (max - min) / 20;

            for (float i = min; i < max; i += window)
            {
                int tmp = getPointCount(dataZ, i, window);
                if (tmp > result)
                {
                    result = tmp;
                    highValue = i;
                }
            }
            
            
            return highValue;
        }
        private int getPointCount(float[] data, float start, float width)
        {
            int count=0;
            for(int i=0;i<data.Length;i++)
            {
                float t = data[i];
                float r = start + width;
                if (data[i] >= start && data[i] <= start+width)
                {
                    count++;
                }
            }
            return count;
        }
        private void findMaxMin(float[] data)
        {
            float low = float.MaxValue,high = float.MinValue;

            for (int i = 0; i < data.Length; i++)
            {
                if (data[i] < low)
                    low = data[i];
                if (data[i] > high)
                    high = data[i];
            }
            max = high;
            min = low;
            //MessageBox.Show("max:"+high.ToString()+"\nmin:"+low.ToString(),"Marching max min" );
        }

        public void resultPlane ()
        {
            
            ////the vertices
            //vertices = new VertexPositionColor[WIDTH*HEIGHT];
            ////configure the vertices data
            //vertices[0].Position = new Vector3(1, 1, -30);
            //vertices[0].Color = Color.White;
            //vertices[1].Position = new Vector3(2, 1, -30);
            //vertices[1].Color = Color.Red;
            //vertices[2].Position = new Vector3(2, 2, -30);
            //vertices[2].Color = Color.White;
            //vertices[3].Position = new Vector3(1, 2, -30);
            //vertices[3].Color = Color.White;
            //vb = new VertexBuffer(myDevice, sizeof(float) * 4 * WIDTH* HEIGHT, BufferUsage.WriteOnly);
            //vb.SetData(vertices);
            
            ///*vertices = new VertexPositionColor[WIDTH * HEIGHT];
            //for (int x = 0; x < WIDTH; x++)
            //{
            //    for (int y = 0; y < HEIGHT; y++)
            //    {
            //        vertices[x + y * WIDTH].Position = new Vector3(x, 10, y);
            //        vertices[x + y * WIDTH].Color = Color.White;
            //    }
            //}

            //vb = new VertexBuffer(myDevice, sizeof(float) * 4 * WIDTH * HEIGHT, BufferUsage.WriteOnly);
            //vb.SetData(vertices);


            //vb = new VertexBuffer(myDevice, sizeof(float) * 4 * WIDTH * HEIGHT, BufferUsage.WriteOnly);
            //vb.SetData(vertices);
            // * */


            ////the indicies
            //int[] indices = new int[(WIDTH - 1) * (HEIGHT - 1) * 3];
            ////set up the indexes
            //for (int x = 0; x < WIDTH - 1; x++)
            //{
            //    for (int y = 0; y < HEIGHT - 1; y++)
            //    {
            //        indices[(x + y * (WIDTH - 1)) * 3] = (x + 1) + (y + 1) * WIDTH;
            //        indices[(x + y * (WIDTH - 1)) * 3 + 1] = (x + 1) + y * WIDTH;
            //        indices[(x + y * (WIDTH - 1)) * 3 + 2] = x + y * WIDTH;
            //    }
            //}
            //ib = new IndexBuffer(myDevice, typeof(int), (WIDTH - 1) * (HEIGHT - 1) * 3, BufferUsage.WriteOnly);
            //ib.SetData(indices);

            //vertices = new VertexPositionColor[4];
            //vertices[0].Position = new Vector3(0, 1, 0f);
            //vertices[0].Color = Color.Red;
            //vertices[1].Position = new Vector3(100, 1, 0f);
            //vertices[1].Color = Color.Green;
            //vertices[2].Position = new Vector3(0, 1, 100);
            //vertices[2].Color = Color.Yellow;
            //vertices[3].Position = new Vector3(100, 1, 100);
            //vertices[3].Color = Color.Yellow;

            vertices = new VertexPositionColor[4];
            vertices[0].Position = new Vector3(-5, 5, location);
            vertices[0].Color = Color.Red;
            vertices[1].Position = new Vector3(-5, -5, location);
            vertices[1].Color = Color.Green;
            vertices[2].Position = new Vector3(5, -5, location);
            vertices[2].Color = Color.Yellow;
            vertices[3].Position = new Vector3(5, 5, location);
            vertices[3].Color = Color.Purple;

            //vertices = new VertexPositionColor[4];
            //vertices[0].Position = new Vector3(1, location, 0);
            //vertices[0].Color = Color.Red;
            //vertices[1].Position = new Vector3(10, location, 0);
            //vertices[1].Color = Color.Green;
            //vertices[2].Position = new Vector3(10, location, -10);
            //vertices[2].Color = Color.Yellow;
            //vertices[3].Position = new Vector3(1, location, -10);
            //vertices[3].Color = Color.Purple;
            //vertices = new VertexPositionColor[4];
            //vertices[0].Position = new Vector3(1, max, 0);
            //vertices[0].Color = Color.Red;
            //vertices[1].Position = new Vector3(10, max, 0);
            //vertices[1].Color = Color.Green;
            //vertices[2].Position = new Vector3(10, max, -10);
            //vertices[2].Color = Color.Yellow;
            //vertices[3].Position = new Vector3(1, max, -10);
            //vertices[3].Color = Color.Purple;


            vb = new VertexBuffer(myDevice, sizeof(float) * 4 * 5, BufferUsage.WriteOnly);
            vb.SetData(vertices);

            short[] indicies = new short[4];
            indicies[0] = 0;
            indicies[1] = 1;
            indicies[2] = 2;
            indicies[3] = 3;

            ib = new IndexBuffer(myDevice, typeof(short), 4, BufferUsage.WriteOnly);
            ib.SetData(indicies);

        }

        protected override void LoadContent()
        {
            //get the device from contructor
            myDevice = myDeviceManager.GraphicsDevice;
            //load the texture
            myTexture = content.Load<Texture2D>(textureAsset);

            //load the shader
            effect = content.Load<Effect>(shaderAsset);

            //vertex declaration
            posColTriangle = new VertexDeclaration(myDevice, VertexPositionColor.VertexElements);

            // executed funtions
            resultPlane();
        }

        public override void Update(GameTime gameTime)
        {
            base.Update(gameTime);
        }

        public override void Draw(GameTime gameTime)
        {
            myDevice.RenderState.CullMode = CullMode.None;


            Matrix wvp = (Matrix.CreateScale(myScale) * Matrix.CreateFromQuaternion(myRotation) * Matrix.CreateTranslation(myPosition)) * Camera.myView * Camera.myProjection;
            effect.Parameters["WorldViewProj"].SetValue(wvp);

            myDevice.VertexDeclaration = posColTriangle;

            //myDevice.RenderState.FillMode = FillMode.WireFrame;
            effect.Begin();
            foreach (EffectPass pass in effect.CurrentTechnique.Passes)
            {

                pass.Begin();
                //draw the plane refering to the location
                //myDevice.DrawIndexedPrimitives(PrimitiveType.TriangleList, 0, 0, WIDTH * HEIGHT, 0, (WIDTH - 1) * (HEIGHT - 1));
                //myDevice.DrawUserIndexedPrimitives(PrimitiveType.TriangleList, vb, 0, WIDTH * HEIGHT, ib, 0, (WIDTH - 1) * (HEIGHT - 1));
                myDevice.DrawUserPrimitives(PrimitiveType.TriangleList, vertices, 0, (WIDTH - 1) * (HEIGHT - 1));
                myDevice.DrawUserPrimitives(PrimitiveType.TriangleStrip, vertices, 0, 2);

                pass.End();

            }
            effect.End();
            //myDevice.RenderState.FillMode = FillMode.Solid;
        }


    }
}
